package cn.topcode.unicorn.utils;

import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

import java.util.*;

/**
 * 动态查询支持工具
 * @author Unicorn
 *
 */
public class DynamicQueryUtil {
	
	//	S(String.class), I(Integer.class), L(Long.class), N(Double.class), D(Date.class), B(Boolean.class), 
	//	G(BigDecimal.class),AS(String[].class), AI(Integer[].class), AL(Long[].class), AN(Double[].class), 
	//	AD(Date[].class), AB(Boolean[].class), AG(BigDecimal[].class);
	//	_OR_查询 EQS_name_OR_sn
	
	//	不支持BigDecimal、BigDecimal[]及OR查询
	
//	private static List<String> OPERATOR = Arrays.asList("EQ","NEQ","GT","GTE","LT","LTE","LIKE","LLIKE","RLIKE","IN","NIN");
	
	private static List<String> TYPE = Arrays.asList("S","I","L","N","D","B",/*"G",*/"AS","AI","AL","AN","AD","AB");

	public static void convert(Map<String,String[]> searchParams, Example example) {
		//	字段排序
		String[] sortFields = searchParams.get("sort");
		if(sortFields != null && sortFields.length > 0) {
			String sort = CollectionUtil.array2String(sortFields);
			String[] orders = searchParams.get("order");
			if(orders != null && orders.length > 0) {
				example.setOrderByClause(sort + " " + orders[0]);
			}else {
				example.setOrderByClause(sort + " asc");
			}
		}

		Criteria criteria = example.createCriteria();
		//	取出所有查询参数名称进行遍历
		Set<String> set = searchParams.keySet();
		for(String originName : set) {
			if(!originName.startsWith("search_")) {
				continue;
			}
			String name = originName.replace("search_","");
			//	对查询参数名称进行分割，正确情况下会得到2个或4个字符串元素
			String[] elements = name.split("_");
			if(elements.length != 2) {
				throw new IllegalArgumentException("动态查询字符串格式有误");
			}
			try {
				String[] values = searchParams.get(originName);
				convert(criteria, elements, values);
			}catch(Exception e) {
				throw new IllegalArgumentException("动态查询字符串解析失败",e);
			}
		}
	}
	
	private static void convert(Criteria criteria, String[] elements, String[] values) {
		//	解析数据类型
		String type = elements[0].substring(elements[0].length() - 2);
		//	解析操作符
		String operator = null;
		if(TYPE.contains(type)) {
			operator = elements[0].substring(0, elements[0].length() - 2);
		}else {
			type = elements[0].substring(elements[0].length() - 1);
			if(TYPE.contains(type)) {
				operator = elements[0].substring(0, elements[0].length() - 1);
			}
		}
		
		Assert.notNull(operator,"动态查询字符串解析失败，无法解析操作符:" + elements[0]);
		String field = elements[1];

		switch(operator) {
			case "EQ": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andEqualTo(field, target);
				break;
			}
			case "NEQ": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andNotEqualTo(field, target);
				break;
			}
			case "GT": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andGreaterThan(field, target);
				break;
			}
			case "GTE": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andGreaterThanOrEqualTo(field, target);
				break;
			}
			case "LT": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andLessThan(field, target);
				break;
			}
			case "LTE": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andLessThanOrEqualTo(field, target);
				break;
			}
			case "LIKE": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andLike(field, "%" + target.toString() + "%");
				break;
			}
			case "LLIKE": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andLike(field, target.toString() + "%");
				break;
			}
			case "RLIKE": {
				Object target = parseValue(type, values);
				if(target != null)
					criteria.andLike(field, "%" + target.toString());
				break;
			}
			case "IN": {
				Object target = parseValues(type, values);
				if(target != null)
					criteria.andIn(field, (Iterable<?>) target);
				break;
			}
			case "NIN": {
				Object target = parseValues(type, values);
				criteria.andNotIn(field, (Iterable<?>) target);
				break;
			}
		}
	}

	private static List parseValues(String type, String[] values) {
		if(values == null || values.length == 0) {
			return null;
		}
		List result = null;
		try {
			switch(type) {
				case "AS":
					result = Arrays.asList(values);
					break;
				case "AI":
				{
					String[] mValueArr = values;
					Integer[] intValues = new Integer[mValueArr.length];
					for(int index = 0 ; index < intValues.length ; index ++ ) {
						intValues[index] = Integer.parseInt(mValueArr[index]);
					}
					result = Arrays.asList(intValues);
				}
				break;
				case "AL":
				{
					String[] mValueArr = values;
					Long[] longValues = new Long[mValueArr.length];
					for(int index = 0 ; index < longValues.length ; index ++ ) {
						longValues[index] = Long.parseLong(mValueArr[index]);
					}
					result = Arrays.asList(longValues);
				}
				break;
				case "AN":
				{
					String[] mValueArr = values;
					Double[] doubleValues = new Double[mValueArr.length];
					for(int index = 0 ; index < doubleValues.length ; index ++ ) {
						doubleValues[index] = Double.parseDouble(mValueArr[index]);
					}
					result = Arrays.asList(doubleValues);
				}
				break;
				case "AD":
				{
					String[] mValueArr = values;
					Date[] dateValues = new Date[mValueArr.length];
					for(int index = 0 ; index < dateValues.length ; index ++ ) {
						dateValues[index] = DateUtil.parse(mValueArr[index],DateUtil.YYYY_MM_DD_24H_MM_SS);
					}
					result = Arrays.asList(dateValues);
				}
				break;
				case "AB":
					String[] mValueArr = values;
					Boolean[] boolValues = new Boolean[mValueArr.length];
					for(int index = 0 ; index < boolValues.length ; index ++ ) {
						boolValues[index] = Boolean.parseBoolean(mValueArr[index]);
					}
					result = Arrays.asList(boolValues);
					break;
			}
			return result;
		}catch(Exception e) {
			throw new IllegalArgumentException("动态查询解析失败 - 数据类型转换错误 type:" + type + ",values:" + values);
		}
	}
	
	private static Object parseValue(String type, String[] values) {
		if(values == null || values.length == 0) {
			return null;
		}
		String value = values[0];
		if(StringUtil.isBlank(value)) {
			return null;
		}
		try {
			Object result = null;
			switch(type) {
			case "S":
				result = value;
				break;
			case "I":
				result = Integer.parseInt(value);
				break;
			case "L":
				result = Long.parseLong(value);
				break;
			case "N":
				result = Double.parseDouble(value);
				break;
			case "D":
				result = DateUtil.parse(value, DateUtil.YYYY_MM_DD_24H_MM_SS);
				break;
			case "B":
				result = Boolean.parseBoolean(value);
				break;
//			case "G":
//				
//				break;
			}
			return result;
		}catch(Exception e) {
			throw new IllegalArgumentException("动态查询解析失败 - 数据类型转换错误 type:" + type + ",value:" + value);
		}
	}
	
}
